package org.summer.lawyer.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.summer.common.core.exception.ServiceException;
import org.summer.common.core.utils.MapstructUtils;
import org.summer.common.mybatis.core.page.PageQuery;
import org.summer.common.mybatis.core.page.TableDataInfo;
import org.summer.lawyer.domain.Article;
import org.summer.lawyer.domain.bo.article.ArticleBrowseBo;
import org.summer.lawyer.domain.vo.article.ArticleCreateVo;
import org.summer.lawyer.domain.vo.article.ArticleUpdateVo;
import org.summer.lawyer.domain.vo.article.ArticleVo;
import org.summer.lawyer.mapper.ArticleMapper;
import org.summer.lawyer.service.IArticleService;
import org.summer.lawyer.util.ParamsUtil;

import java.util.Collection;
import java.util.Map;

/**
 *
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {


    @Override
    public TableDataInfo<ArticleVo> selectListPage(ArticleVo vo, PageQuery pageQuery) {
        if (PageQuery.DEFAULT_PAGE_SIZE == pageQuery.getPageSize()) {
            return TableDataInfo.build(baseMapper.selectVoList(buildQueryWrapper(vo)));
        }
        Page<ArticleVo> page = baseMapper.selectVoPage(pageQuery.build(), buildQueryWrapper(vo));
        return TableDataInfo.build(page);
    }

    @Override
    public ArticleVo selectArticleVoById(Long id) {
        ArticleVo vo = baseMapper.selectVoById(id);
        if(ObjectUtil.isNotNull(vo)){
            ArticleVo nextArticle = selectNextArticleByArticleId(vo.getArticleId());
            if(ObjectUtil.isNotNull(nextArticle)){
                vo.setNextArticleId(nextArticle.getArticleId());
                vo.setNextArticleTitle(nextArticle.getTitle());
            }
        }
        return vo;
    }

    private Wrapper<Article> buildQueryWrapper(ArticleVo vo) {
        Map<String, Object> params = ParamsUtil.getParams(vo.getParams());
        LambdaQueryWrapper<Article> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(StrUtil.isNotBlank(vo.getStatus()), Article::getStatus, vo.getStatus())
                .eq(StrUtil.isNotBlank(vo.getCategoryId()) && !"0".equals(vo.getCategoryId()), Article::getCategoryId, vo.getCategoryId())
                .eq(StrUtil.isNotBlank(vo.getCurated()), Article::getCurated, vo.getCurated())
                .like(StrUtil.isNotBlank(vo.getTitle()), Article::getTitle, vo.getTitle())
                .between(params.get("beginTime") != null && params.get("endTime") != null, Article::getPublishedTime, params.get("beginTime"), params.get("endTime"))
                .orderByDesc(Article::getArticleId);
        return queryWrapper;
    }

    @Override
    public void saveArticle(ArticleCreateVo vo) {
        Article article = new Article();
        MapstructUtils.convert(vo, article);
        article.setPublishedTime(DateUtil.date());
        if("0".equals(article.getStatus())) {
            article.setPublishedTime(null);
        }
        baseMapper.insert(article);
    }

    @Override
    public void updateArticle(ArticleUpdateVo vo) {
        Article article = new Article();
        MapstructUtils.convert(vo, article);
        article.setPublishedTime(DateUtil.date());
        if("0".equals(article.getStatus())) {
            article.setPublishedTime(null);
        }
        LambdaUpdateWrapper<Article> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(Article::getArticleId, vo.getArticleId());
        baseMapper.update(article, updateWrapper);
    }

    @DSTransactional(rollbackFor = Exception.class)
    @Override
    public void deleteArticleByIds(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            throw new ServiceException("主键不能为空");
        }
        ids.forEach(id -> {
            baseMapper.deleteById(id);
        });
    }

    @Override
    public void changeArticleStatus(ArticleVo vo) {
        Article article = baseMapper.selectById(vo.getArticleId());
        if (ObjectUtil.isNull(article)) {
            throw new ServiceException("未找到文章信息");
        }
        LambdaUpdateWrapper<Article> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(Article::getArticleId, vo.getArticleId())
                .set(Article::getStatus, vo.getStatus());
        baseMapper.update(updateWrapper);
    }

    @Lock4j(keys = {"#bo.articleId"}, acquireTimeout = 1000, expire = 10000)
    @Override
    public void saveArticleBrowse(ArticleBrowseBo bo) {
        ArticleVo vo = selectArticleVoById(bo.getArticleId());
        if (ObjectUtil.isNotNull(vo)) {
            int totalViews = vo.getTotalView() + 1;
            LambdaUpdateWrapper<Article> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.eq(Article::getArticleId, bo.getArticleId())
                    .set(Article::getTotalView, totalViews);
            baseMapper.update(updateWrapper);
        }
    }

    @Override
    public ArticleVo selectNextArticleByArticleId(Long articleId) {
        return baseMapper.selectNextArticleByArticleId(articleId);
    }

    @Override
    public void updateArticleTotalUpvote(ArticleVo vo) {
        Article article = new Article();
        article.setArticleId(vo.getArticleId());
        article.setTotalUpvote(vo.getTotalUpvote());
        LambdaUpdateWrapper<Article> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(Article::getArticleId, vo.getArticleId());
        baseMapper.update(article,updateWrapper);
    }
}
